package com.ramblingcoder.bc2.server.tool.update.objects;

import java.io.IOException;
import java.net.Socket;

import com.ramblingcoder.bc2.server.tool.update.commands.Parcel;
import com.ramblingcoder.bc2.server.tool.update.commands.SupportingFunctions;
import com.ramblingcoder.bc2.server.tool.update.exceptions.InvalidArguments;
import com.ramblingcoder.bc2.server.tool.update.exceptions.InvalidConfig;
import com.ramblingcoder.bc2.server.tool.update.exceptions.InvalidNrOfPlayers;
import com.ramblingcoder.bc2.server.tool.update.exceptions.InvalidPassword;
import com.ramblingcoder.bc2.server.tool.update.exceptions.LevelNotLoaded;
import com.ramblingcoder.bc2.server.tool.update.exceptions.LogInRequired;
import com.ramblingcoder.bc2.server.tool.update.exceptions.StartupOnlyCallNotAllowed;
import com.ramblingcoder.bc2.server.tool.update.exceptions.TooLongDescription;
import com.ramblingcoder.bc2.server.tool.update.exceptions.TooLongUrl;

public class Server {
	//Variables-----\
	public static final int GET = -1;
	public static final int NO = 0;
	public static final int YES = 1;
	
	private String name, ip, port, pass;
	//Variables-----/
	
	//Constructor-----\
	public Server(String name, String ip, String port, String pass) {
		this.name = name;
		this.ip = ip;
		this.port = port;
		this.pass = pass;
	}
	//Constructor-----/
	
	//Support-----\
	public static Server[] parseServer(String serverChoices) {
		if (serverChoices.equals(""))
			return new Server[0];
		
		String[] serverData = serverChoices.split(";");
		
		Server[] servers = new Server[serverData.length];
		
		for (int i = 0; i < serverData.length; i++){
			String data = serverData[i];
			
			int nameStart = data.indexOf("{")+1;
			int nameEnd = data.indexOf("}");
			
			int ipStart = data.indexOf("<")+1;
			int ipEnd = data.indexOf(">");
	
			int portStart = data.indexOf("(")+1;
			int portEnd = data.indexOf(")");
	
			int passStart = data.indexOf("[")+1;
			int passEnd = data.indexOf("]");
			
			String
				name = data.substring(nameStart, nameEnd), 
				ip = data.substring(ipStart, ipEnd), 
				port = data.substring(portStart, portEnd), 
				pass = data.substring(passStart, passEnd);
			
			servers[i] = new Server(name, ip, port, pass);
		}
		
		return servers;
	}
	
	public static String compileServer(Server[] servers){
		String compiled = "";

		if (servers != null)
			for (int i = 0; i < servers.length; i++) {
				Server server = servers[i];
				
				if (server != null)
					compiled += server.getCompiled() + (i != servers.length-1 ? ";" : "");
			}
		
		return compiled;
	}
	
	public static String compileServer(Server[] servers, Server serverAdd){
		String compiled = "";

		if (servers != null)
			for (Server server : servers)
				if (server != null)
					compiled += server.getCompiled() + ";";
		
		compiled += serverAdd.getCompiled();
		
		return compiled;
	}
	
	public static String[] getServerInfo(Socket socket) throws IOException, InvalidArguments{
		SupportingFunctions.sendCommand(socket.getOutputStream(), new String[]{"serverInfo"});
		Parcel response = SupportingFunctions.getResponse(socket.getInputStream())[0];
		
		if (response.getStatus().equals("OK"))
			return response.getWordsTrimmed();
		else if (response.getStatus().equals("InvalidArguments"))
			throw new InvalidArguments();
		
		return null;
	}
	
	public static String[] getServerVersion(Socket socket) throws IOException, InvalidArguments{
		SupportingFunctions.sendCommand(socket.getOutputStream(), new String[]{"version"});
		Parcel response = SupportingFunctions.getResponse(socket.getInputStream())[0];
		
		if (response.getStatus().equals("OK"))
			return response.getWordsTrimmed();
		else if (response.getStatus().equals("InvalidArguments"))
			throw new InvalidArguments();
		
		return null;
	}
	
	//----------------------------------------------------------------------------------------------------
	public static boolean enableEvents(Socket socket, int getyesno) throws IOException, InvalidArguments, LogInRequired{
		if (getyesno == GET)
			SupportingFunctions.sendCommand(socket.getOutputStream(), new String[]{"eventsEnabled"});
		else
			SupportingFunctions.sendCommand(socket.getOutputStream(), new String[]{"eventsEnabled", (getyesno == NO ? "false" : "true")});
		
		Parcel response = SupportingFunctions.getResponse(socket.getInputStream())[0];
		
		if (response.getStatus().equals("OK"))
			if (getyesno == GET)
				return (response.getWords()[1].equals("true") ? true : false);
			else
				return true;
		else if (response.getStatus().equals("InvalidArguments"))
			throw new InvalidArguments();
		else if (response.getStatus().equals("LogInRequired"))
			throw new LogInRequired();
		
		return false;
	}
	
	public static boolean punkbusterEnabled(Socket socket, int getyesno) throws IOException, InvalidArguments, LogInRequired, InvalidConfig, StartupOnlyCallNotAllowed{
		if (getyesno == GET)
			SupportingFunctions.sendCommand(socket.getOutputStream(), new String[]{"vars.punkBuster"});
		else
			SupportingFunctions.sendCommand(socket.getOutputStream(), new String[]{"vars.punkBuster", (getyesno == NO ? "false" : "true")});
		
		Parcel response = SupportingFunctions.getResponse(socket.getInputStream())[0];
		
		if (response.getStatus().equals("OK"))
			if (getyesno == GET)
				return (response.getWords()[1].equals("true") ? true : false);
			else
				return true;
		else if (response.getStatus().equals("InvalidArguments"))
			throw new InvalidArguments();
		else if (response.getStatus().equals("LogInRequired"))
			throw new LogInRequired();
		else if (response.getStatus().equals("InvalidConfig"))
			throw new InvalidConfig("'PunkBuster' can not be disabled while 'Ranked' is enabled.");
		else if (response.getStatus().equals("StartupOnlyCallNotAllowed"))
			throw new StartupOnlyCallNotAllowed();
		
		return false;
	}
	
	public static boolean friendlyFireEnabled(Socket socket, int getyesno) throws IOException, LevelNotLoaded, LogInRequired, InvalidArguments {
		if (getyesno == GET)
			SupportingFunctions.sendCommand(socket.getOutputStream(), new String[]{"vars.friendlyFire"});
		else
			SupportingFunctions.sendCommand(socket.getOutputStream(), new String[]{"vars.friendlyFire", (getyesno == NO ? "false" : "true")});
		
		Parcel response = SupportingFunctions.getResponse(socket.getInputStream())[0];
		
		if (response.getStatus().equals("OK"))
			if (getyesno == GET)
				return (response.getWords()[1].equals("true") ? true : false);
			else
				return true;
		else if (response.getStatus().equals("InvalidArguments"))
			throw new InvalidArguments();
		else if (response.getStatus().equals("LogInRequired"))
			throw new LogInRequired();
		else if (response.getStatus().equals("LevelNotLoaded"))
			throw new LevelNotLoaded();
		
		return false;
	}
	
	public static int rankLimit(Socket socket, int getyesno) throws IOException, InvalidArguments, LogInRequired{
		if (getyesno == GET)
			SupportingFunctions.sendCommand(socket.getOutputStream(), new String[]{"vars.rankLimit"});
		else
			SupportingFunctions.sendCommand(socket.getOutputStream(), new String[]{"vars.rankLimit", (getyesno == NO ? "false" : "true")});
		
		Parcel response = SupportingFunctions.getResponse(socket.getInputStream())[0];
		
		if (response.getStatus().equals("OK"))
			return Integer.parseInt(response.getWords()[1]);
		else if (response.getStatus().equals("InvalidArguments"))
			throw new InvalidArguments();
		else if (response.getStatus().equals("LogInRequired"))
			throw new LogInRequired();
			
		return -1;
	}

	public static boolean ranked(Socket socket, int getyesno) throws IOException, InvalidArguments, LogInRequired, StartupOnlyCallNotAllowed{
		if (getyesno == GET)
			SupportingFunctions.sendCommand(socket.getOutputStream(), new String[]{"vars.ranked"});
		else
			SupportingFunctions.sendCommand(socket.getOutputStream(), new String[]{"vars.ranked", (getyesno == NO ? "false" : "true")});
		Parcel response = SupportingFunctions.getResponse(socket.getInputStream())[0];
		
		if (response.getStatus().equals("OK"))
			if (getyesno == GET)
				return (response.getWords()[1].equals("true") ? true : false);
			else
				return true;
		else if (response.getStatus().equals("InvalidArguments"))
			throw new InvalidArguments();
		else if (response.getStatus().equals("LogInRequired"))
			throw new LogInRequired();
		else if (response.getStatus().equals("StartupOnlyCallNotAllowed"))
			throw new StartupOnlyCallNotAllowed();
			
		return false;
	}

	public static boolean teamBalance(Socket socket, int getyesno) throws IOException, LogInRequired, InvalidArguments{
		if (getyesno == GET)
			SupportingFunctions.sendCommand(socket.getOutputStream(), new String[]{"vars.teamBalance"});
		else
			SupportingFunctions.sendCommand(socket.getOutputStream(), new String[]{"vars.teamBalance", (getyesno == NO ? "false" : "true")});
		
		Parcel response = SupportingFunctions.getResponse(socket.getInputStream())[0];
		
		if (response.getStatus().equals("OK"))
			if (getyesno == GET)
				return (response.getWords()[1].equals("true") ? true : false);
			else
				return true;
		else if (response.getStatus().equals("InvalidArguments"))
			throw new InvalidArguments();
		else if (response.getStatus().equals("LogInRequired"))
			throw new LogInRequired();
		
		return false;
	}
	
	
	public static String bannerUrl(Socket socket, String url) throws IOException, TooLongUrl, LogInRequired, InvalidArguments{
		if (url == null)
			SupportingFunctions.sendCommand(socket.getOutputStream(), new String[]{"vars.bannerUrl"});
		else 
			SupportingFunctions.sendCommand(socket.getOutputStream(), new String[]{"vars.bannerUrl", url});
		
		Parcel response = SupportingFunctions.getResponse(socket.getInputStream())[0];
		
		if (response.getStatus().equals("OK"))
			if (url == null)
				return response.getWords()[1];
		else if (response.getStatus().equals("InvalidArguments"))
			throw new InvalidArguments();
		else if (response.getStatus().equals("LogInRequired"))
			throw new LogInRequired();
		else if (response.getStatus().equals("TooLongUrl"))
			throw new TooLongUrl("Max url length is 64 characters. Banner must be 512x64.");
		
		return null;
	}

	public static boolean spotting3D(Socket socket, int getyesno) throws IOException, LogInRequired, InvalidArguments {
		if (getyesno == GET)
			SupportingFunctions.sendCommand(socket.getOutputStream(), new String[]{"vars.3dSpotting"});
		else
			SupportingFunctions.sendCommand(socket.getOutputStream(), new String[]{"vars.3dSpotting", (getyesno == NO ? "false" : "true")});
		
		Parcel response = SupportingFunctions.getResponse(socket.getInputStream())[0];
		
		if (response.getStatus().equals("OK"))
			if (getyesno == GET)
				return (response.getWords()[1].equals("true") ? true : false);
			else
				return true;
		else if (response.getStatus().equals("InvalidArguments"))
			throw new InvalidArguments();
		else if (response.getStatus().equals("LogInRequired"))
			throw new LogInRequired();
		
		return false;
	}
	
	public static boolean vehicleCamera(Socket socket, int getyesno) throws IOException, LogInRequired, InvalidArguments {
		if (getyesno == GET)
			SupportingFunctions.sendCommand(socket.getOutputStream(), new String[]{"vars.thirdPersonVehicleCameras"});
		else
			SupportingFunctions.sendCommand(socket.getOutputStream(), new String[]{"vars.thirdPersonVehicleCameras", (getyesno == NO ? "false" : "true")});
		
		Parcel response = SupportingFunctions.getResponse(socket.getInputStream())[0];
		
		if (response.getStatus().equals("OK"))
			if (getyesno == GET)
				return (response.getWords()[1].equals("true") ? true : false);
			else
				return true;
		else if (response.getStatus().equals("InvalidArguments"))
			throw new InvalidArguments();
		else if (response.getStatus().equals("LogInRequired"))
			throw new LogInRequired();
		
		return false;
	}
	
	public static boolean crossHair(Socket socket, int getyesno) throws IOException, LogInRequired, InvalidArguments {
		if (getyesno == GET)
			SupportingFunctions.sendCommand(socket.getOutputStream(), new String[]{"vars.crossHair"});
		else
			SupportingFunctions.sendCommand(socket.getOutputStream(), new String[]{"vars.crossHair", (getyesno == NO ? "false" : "true")});
		
		Parcel response = SupportingFunctions.getResponse(socket.getInputStream())[0];
		
		if (response.getStatus().equals("OK"))
			if (getyesno == GET)
				return (response.getWords()[1].equals("true") ? true : false);
			else
				return true;
		else if (response.getStatus().equals("InvalidArguments"))
			throw new InvalidArguments();
		else if (response.getStatus().equals("LogInRequired"))
			throw new LogInRequired();
		
		return false;
	}
	
	public static boolean hardCore(Socket socket, int getyesno) throws IOException, LogInRequired, InvalidArguments {
		if (getyesno == GET)
			SupportingFunctions.sendCommand(socket.getOutputStream(), new String[]{"vars.hardCore"});
		else
			SupportingFunctions.sendCommand(socket.getOutputStream(), new String[]{"vars.hardCore", (getyesno == NO ? "false" : "true")});
			
		Parcel response = SupportingFunctions.getResponse(socket.getInputStream())[0];
		
		if (response.getStatus().equals("OK"))
			if (getyesno == GET)
				return (response.getWords()[1].equals("true") ? true : false);
			else
				return true;
		else if (response.getStatus().equals("InvalidArguments"))
			throw new InvalidArguments();
		else if (response.getStatus().equals("LogInRequired"))
			throw new LogInRequired();
		
		return false;
	}
	
	public static boolean killCam(Socket socket, int getyesno) throws IOException, LogInRequired, InvalidArguments {
		if (getyesno == GET)
			SupportingFunctions.sendCommand(socket.getOutputStream(), new String[]{"vars.killCam"});
		else 
			SupportingFunctions.sendCommand(socket.getOutputStream(), new String[]{"vars.killCam", (getyesno == NO ? "false" : "true")});
		
		Parcel response = SupportingFunctions.getResponse(socket.getInputStream())[0];
		
		if (response.getStatus().equals("OK"))
			if (getyesno == GET)
				return (response.getWords()[1].equals("true") ? true : false);
			else
				return true;
		else if (response.getStatus().equals("InvalidArguments"))
			throw new InvalidArguments();
		else if (response.getStatus().equals("LogInRequired"))
			throw new LogInRequired();
		
		return false;
	}
	
	public static boolean miniMap(Socket socket, int getyesno) throws IOException, LogInRequired, InvalidArguments {
		if (getyesno == GET)
			SupportingFunctions.sendCommand(socket.getOutputStream(), new String[]{"vars.miniMap"});
		else 
			SupportingFunctions.sendCommand(socket.getOutputStream(), new String[]{"vars.miniMap", (getyesno == NO ? "false" : "true")});
		
		Parcel response = SupportingFunctions.getResponse(socket.getInputStream())[0];
		
		if (response.getStatus().equals("OK"))
			if (getyesno == GET)
				return (response.getWords()[1].equals("true") ? true : false);
			else
				return true;
		else if (response.getStatus().equals("InvalidArguments"))
			throw new InvalidArguments();
		else if (response.getStatus().equals("LogInRequired"))
			throw new LogInRequired();
		
		return false;
	}
	
	public static boolean miniMapSpotting(Socket socket, int getyesno) throws IOException, LogInRequired, InvalidArguments {
		if (getyesno == GET)
			SupportingFunctions.sendCommand(socket.getOutputStream(), new String[]{"vars.miniMapSpotting"});
		else 
			SupportingFunctions.sendCommand(socket.getOutputStream(), new String[]{"vars.miniMapSpotting", (getyesno == NO ? "false" : "true")});
		
		Parcel response = SupportingFunctions.getResponse(socket.getInputStream())[0];
		
		if (response.getStatus().equals("OK"))
			if (getyesno == GET)
				return (response.getWords()[1].equals("true") ? true : false);
			else
				return true;
		else if (response.getStatus().equals("InvalidArguments"))
			throw new InvalidArguments();
		else if (response.getStatus().equals("LogInRequired"))
			throw new LogInRequired();
		
		return false;
	}
	
	/** set description to null to retrieve */
	public static String description(Socket socket, String description) throws IOException, TooLongDescription, LogInRequired, InvalidArguments {
		if (description == null)
			SupportingFunctions.sendCommand(socket.getOutputStream(), new String[]{"vars.serverDescription"});
		else
			SupportingFunctions.sendCommand(socket.getOutputStream(), new String[]{"vars.serverDescription", description});
		
		Parcel response = SupportingFunctions.getResponse(socket.getInputStream())[0];
		
		if (response.getStatus().equals("OK"))
			if (description == null)
				return response.getWords()[1];
		else if (response.getStatus().equals("InvalidArguments"))
			throw new InvalidArguments();
		else if (response.getStatus().equals("LogInRequired"))
			throw new LogInRequired();
		else if (response.getStatus().equals("TooLongDescription"))
			throw new TooLongDescription("Description to set was too long. Max character length is 400.");
		
		return null;
	}

	public static String gamePwd(Socket socket, String password) throws IOException, InvalidPassword, InvalidConfig, LogInRequired, InvalidArguments {
		if (password == null)
			SupportingFunctions.sendCommand(socket.getOutputStream(), new String[]{"vars.gamePassword"});
		else
			SupportingFunctions.sendCommand(socket.getOutputStream(), new String[]{"vars.gamePassword", password});
		
		Parcel response = SupportingFunctions.getResponse(socket.getInputStream())[0];

		if (response.getStatus().equals("OK"))
			if (password == null)
				return response.getWords()[1];
		else if (response.getStatus().equals("InvalidArguments"))
			throw new InvalidArguments();
		else if (response.getStatus().equals("LogInRequired"))
			throw new LogInRequired();
		else if (response.getStatus().equals("InvalidPassword"))
			throw new InvalidPassword();
		else if (response.getStatus().equals("InvalidConfig"))
			throw new InvalidConfig("Password can not be set while 'Ranked' is enabled.");

		return null;
	}
	
	public static String adminPwd(Socket socket, String password) throws IOException, InvalidPassword, LogInRequired, InvalidArguments {
		if (password == null)
			SupportingFunctions.sendCommand(socket.getOutputStream(), new String[]{"vars.adminPassword"});
		else
			SupportingFunctions.sendCommand(socket.getOutputStream(), new String[]{"vars.adminPassword", password});
		
		Parcel response = SupportingFunctions.getResponse(socket.getInputStream())[0];

		if (response.getStatus().equals("OK"))
			if (password == null)
				return response.getWords()[1];
		else if (response.getStatus().equals("InvalidArguments"))
			throw new InvalidArguments();
		else if (response.getStatus().equals("LogInRequired"))
			throw new LogInRequired();
		else if (response.getStatus().equals("InvalidPassword"))
			throw new InvalidPassword();

		return null;
	}

	public static int playerLimit(Socket socket, int getORnumber) throws IOException, InvalidNrOfPlayers, LogInRequired, InvalidArguments {
		if (getORnumber == GET)
			SupportingFunctions.sendCommand(socket.getOutputStream(), new String[]{"vars.playerLimit"});
		else
			SupportingFunctions.sendCommand(socket.getOutputStream(), new String[]{"vars.playerLimit", getORnumber+""});
			
		Parcel response = SupportingFunctions.getResponse(socket.getInputStream())[0];

		if (response.getStatus().equals("OK"))
			if (getORnumber == GET)
				return Integer.parseInt(response.getWords()[1]);
			else
				return 0;
		else if (response.getStatus().equals("InvalidArguments"))
			throw new InvalidArguments();
		else if (response.getStatus().equals("LogInRequired"))
			throw new LogInRequired();
		else if (response.getStatus().equals("InvalidNrOfPlayers"))
			throw new InvalidNrOfPlayers("Invalid amount of players. Number between 8 to 32.");
			
		return -1;
	}

	public static int maxPlayerLimit(Socket socket) throws IOException, LogInRequired, InvalidArguments {
		SupportingFunctions.sendCommand(socket.getOutputStream(), new String[]{"vars.maxPlayerLimit"});
			
		Parcel response = SupportingFunctions.getResponse(socket.getInputStream())[0];

		if (response.getStatus().equals("OK"))
			return Integer.parseInt(response.getWords()[1]);
		else if (response.getStatus().equals("InvalidArguments"))
			throw new InvalidArguments();
		else if (response.getStatus().equals("LogInRequired"))
			throw new LogInRequired();
		
		return -1;
	}

	public static int idleTimeout(Socket socket, int getORnumber) throws IOException, LogInRequired, InvalidArguments {
		if (getORnumber == GET)
			SupportingFunctions.sendCommand(socket.getOutputStream(), new String[]{"vars.idleTimeout"});
		else
			SupportingFunctions.sendCommand(socket.getOutputStream(), new String[]{"vars.idleTimeout", getORnumber+""});
			
		Parcel response = SupportingFunctions.getResponse(socket.getInputStream())[0];

		if (response.getStatus().equals("OK"))
			if (getORnumber == GET)
				return Integer.parseInt(response.getWords()[1]);
			else
				return 0;
		else if (response.getStatus().equals("InvalidArguments"))
			throw new InvalidArguments();
		else if (response.getStatus().equals("LogInRequired"))
			throw new LogInRequired();
			
		return -1;
	}
	
	public static boolean profanity(Socket socket, int getyesno) throws IOException, InvalidArguments, LogInRequired{
		if (getyesno == GET)
			SupportingFunctions.sendCommand(socket.getOutputStream(), new String[]{"vars.profanityFilter"});
		else
			SupportingFunctions.sendCommand(socket.getOutputStream(), new String[]{"vars.profanityFilter", (getyesno == NO ? "false" : "true")});
		
		Parcel response = SupportingFunctions.getResponse(socket.getInputStream())[0];
		
		if (response.getStatus().equals("OK"))
			if (getyesno == GET)
				return (response.getWords()[1].equals("true") ? true : false);
			else
				return true;
		else if (response.getStatus().equals("InvalidArguments"))
			throw new InvalidArguments();
		else if (response.getStatus().equals("LogInRequired"))
			throw new LogInRequired();
		
		return false;
	}
	//Support-----/
	
	//Getters-----\
	public String getIp() {
		return ip;
	}
	public String getPass() {
		return pass;
	}
	public int getPort() {
		return Integer.parseInt(port);
	}
	public String getName() {
		return name;
	}
	public String getAddress(){
		return ip + ":" + port;
	}
	public String getDisplay(){

//		String[] ips = getIp().split("\\.");
//		
//		DecimalFormat format = new DecimalFormat("000");
//		for (int i = 0; i < ips.length; i++){
//			ips[i] = format.format(Integer.parseInt(ips[i]));
//		}
//		
//		String ip = "";
//		
//		for (String ipPart : ips)
//			ip += ipPart + ".";
//		
//		ip = ip.substring(0, ip.length()-1);
		
		return getIp() + ":" + getPort() + " " + name;
	}
	public String getCompiled(){
		return "{" + name + "}<" + ip + ">(" + port + ")[" + pass + "]";
	}
	//Getters-----/
}
